#ifndef					_BSPLINEANIMATOR_H_
#define					_BSPLINEANIMATOR_H_

#include "Irrlicht/irrlicht.h"

class CBSplineAnimator : public ISceneNodeAnimator
{
public: 
	CBSplineAnimator(u32 time, core::array<core::vector3df> points, f32 speed = 1.0f);
	virtual ~CBSplineAnimator ();
	virtual void animateNode (scene::ISceneNode *node, u32 timeMs);

protected:
	int clamp(s32 idx, u32 size);

	core::array<core::vector3df> mPoints;
	u32 mStartTime;
	f32 mSpeed;
};


CBSplineAnimator::CBSplineAnimator(u32 time, core::array<core::vector3df> points, f32 speed) 
{
	mStartTime = time;
	mPoints = points;
	mSpeed = speed;
}

CBSplineAnimator::~CBSplineAnimator ()
{
}


inline int CBSplineAnimator::clamp(s32 idx, u32 size) 
{
	return ( idx<0 ? 0 : ( idx>=size ? size-1 : idx ) );
}


void CBSplineAnimator::animateNode (scene::ISceneNode *node, u32 timeMs)
{ 
	u32 pSize = mPoints.size();    

	const f32 dt = ( (timeMs-mStartTime) * mSpeed * 0.001f );
	const f32 u = core::fract ( dt );
	s32 idx = core::floor32( dt ) % (pSize+1); 
	f32 iu = 1.0f-u;

	float b0 = iu * iu * iu / 6.0f;
	float b1 = ( 3 * u * u * u - 6 * u * u + 4 ) / 6.0f;
	float b2 = (-3 * u * u * u + 3 * u * u + 3* u + 1 ) /6.0f;
	float b3 = u * u * u /6.0f;     

	core::vector3df f, p0, p1, p2, p3;
	p0 = mPoints[ clamp( idx-2, pSize ) ];
	p1 = mPoints[ clamp( idx-1, pSize ) ];
	p2 = mPoints[ clamp( idx+0, pSize ) ];
	p3 = mPoints[ clamp( idx+1, pSize ) ]; 

	f = b0 * p0 + b1 * p1 + b2 * p2 + b3 * p3;        

	// set node orientation
	core::vector3df direction = node->getPosition() - f;
	node->setRotation(direction.getHorizontalAngle());

	// set node position
	node->setPosition(f);    
}

#endif					//_BSPLINEANIMATOR_H_

